#include "game_server.h"
#include "wrap_directinputdevice8.h"
#include "wrap_directinputeffect.h"
#include "opcode.h"


DIMOUSESTATE mouse;
DIMOUSESTATE2 mouse2;
char keyboard[256];      // global buffer for the input device
bool mouse_acquired = false;
bool keyboard_acquired = false;
// define the list to store effect
HashSet Effect_list;

struct key_events{
	DIDEVICEOBJECTDATA datas[100];
	int counts;
	bool acquired;
	int to_get;
	DWORD cbObjectData;
	DWORD dwFlags;
}Keyboard_events;
struct mouse_events{
	DIDEVICEOBJECTDATA datas[100];
	int counts;
	bool acquired;
	int to_get;
	DWORD cbObjectData;
	DWORD dwFlags;
}Mouse_events;

bool WriteDIDObjectData(LPDIDEVICEOBJECTDATA a,LPDIDEVICEOBJECTDATA src){
	a->dwOfs = src->dwOfs;
	a->dwData = src->dwData;
	a->dwSequence = src->dwSequence;
	a->dwTimeStamp = src->dwTimeStamp;
	a->uAppData = src->uAppData;
	return true;
}


int WrapperDirectInputDevice8::GetID(){
	return this->id;
}

void WrapperDirectInputDevice8::SetID(int id){
	this->id = id;
}

WrapperDirectInputDevice8::WrapperDirectInputDevice8(IDirectInputDevice8 *ptr,int _id){
	Log::log("WrapperDirectInputDevice8::Constructor() called!\n");
	this->m_device = ptr;
	this->id = _id;
}
/*Unknown methods*/
STDMETHODIMP WrapperDirectInputDevice8::QueryInterface(THIS_ REFIID riid, void ** ppvObj){
	Log::log("WrapperDirectInputDevice8::QueryInterface() called!\n");
	HRESULT hr = m_device->QueryInterface(riid,ppvObj);
	*ppvObj = this;
	return hr;
}

STDMETHODIMP_(ULONG) WrapperDirectInputDevice8::AddRef(THIS){
	Log::log("WrapperDirectInputDevice8::AddRef() called!\n");
	//cs.begin_command(DIDAddRef_Opcode, id);
	//cs.end_command();
	
	return this->m_device->AddRef();
}

STDMETHODIMP_(ULONG) WrapperDirectInputDevice8::Release(THIS){
	Log::log("WrapperDirectInputDevice8::Release() called!\n");
	//cs.begin_command(DIDRelease_Opcode, id);
	//cs.end_command();
	return this->m_device->Release();
}

/* IDirectInputDevice8 methods*/
/*
Obtains access to the input device. no need to feedback
*/
STDMETHODIMP WrapperDirectInputDevice8::Acquire(THIS){
	//HRESULT hr = m_device->Acquire();
	Log::log("WrapperDirectInputDevice8::Acquire called, Obtains access to the input device\n");
	// send calls
	cs.begin_command(DIDAcquire_Opcode, id);
	
	//WRITE_DATA(int ,id);
	cs.write_char(this->tag);
	cs.end_command();

	//int len = recv(client.clientSocket,msg,sizeof(msg),0);
	//DIERR_INVALIDPARAM, DIERR_NOTINITIALIZED, DIERR_OTHERAPPHA
	HRESULT th;//= (HRESULT)msg;
	switch(th){
	case DIERR_INVALIDPARAM:
		Log::log("Acquire() return DIERR_INVALIDPARAM\n");
		break;
	case DIERR_NOTINITIALIZED:
		Log::log("Acquire() return DIERR_NOTINITIALIZED\n");
		break;
	case DIERR_OTHERAPPHASPRIO:
		Log::log("Acquire() return DIERR_OTHERAPPHASPRIO\n");
		break;
	case DI_OK:
		Log::log("Acquire() return DI_OK\n");
		break;
	case S_FALSE:
		Log::log("Acquire() return S_FALSE\n");
		break;
	default:
		Log::log("Acquire() return Unknown\n");
		break;
	}
	//return th;
	return DI_OK;
}
/*
Builds an action map for the device and retrieves information about it.
sychronize it to client
*/
STDMETHODIMP WrapperDirectInputDevice8::BuildActionMap(THIS_ LPDIACTIONFORMAT lpdiaf,LPCTSTR lpszUserName,DWORD dwFlags){
	Log::log("WrapperDirectInputDevice::BuildActionMap called, builds an action map for the device and retrieves information about it.\n");

	HRESULT hr = m_device->BuildActionMap(lpdiaf,lpszUserName,dwFlags);
	// send calls, LPDIACTIONFORMAT local param
	//cs.begin_command(DIDBuildActionMap_Opcode, id);
	//cs.write_char(this->tag);

	
	//WRITE_DATA(DIACTIONFORMAT, *lpdiaf);
	cs.write_int(dwFlags);
	
	
	//cs.end_command();
	return hr;
}
/*
Creates and initializes an instance of an effect identified by the effect globally unique identifier (GUID).
*/
STDMETHODIMP WrapperDirectInputDevice8::CreateEffect(THIS_ REFGUID rguid, LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT * ppdeff, LPUNKNOWN punkOuter){
	Log::log("WrapperDirectInputDevice8::CreateEffect() called!\n");
	

	LPDIRECTINPUTEFFECT base_effect = NULL;
	HRESULT hr = m_device->CreateEffect(rguid,lpeff,&base_effect,punkOuter);

	//cs.begin_command(DIDCreateEffect_Opcode, id);
	//cs.write_int(WrapperDirectInputEffect::ins_count);

	//WRITE_DATA(GUID, rguid);
	//WRITE_DATA(DIEFFECT, *lpeff);

	//cs.end_command();

	WrapperDirectInputEffect::ins_count ++;
	//send calls, LPDIRECTINPUTEFFECT localed param
	if(SUCCEEDED(hr)){
		WrapperDirectInputEffect * eff = new WrapperDirectInputEffect(base_effect,WrapperDirectInputEffect::ins_count - 1);
		*ppdeff = static_cast<IDirectInputEffect *>(eff);
		Effect_list.AddMember(eff,this);

	}else
	{
		Log::log("Create DirectInputEffect failed!\n");
	}

	return hr;
}
/*
Enumerates all the currently created effects for this device. Effects created by IDirectInputDevice8::CreateEffect are enumerated.
*/
STDMETHODIMP WrapperDirectInputDevice8::EnumCreatedEffectObjects(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID pvRef,  DWORD fl){
	Log::log("WrapperDirectInputDevice8::EnumCreatedEffectObjects() called!\n");
	HRESULT hr = m_device->EnumCreatedEffectObjects(lpCallback,pvRef,fl);
	// send calls, all param localed

	//GET_BUFFER(DIDEnumCreateEffectObjects_Opcode, id);
	//WRITE_DATA(DWORD ,fl);

	//END_BUFFER();
	//client.SendPacket(msg, buf_size);

	return hr;
}
/*
Enumerates all the effects supported by the force-feedback system on the device. The enumerated GUIDs can represent predefined effects, as well as effects peculiar to the device manufacturer.
*/
STDMETHODIMP WrapperDirectInputDevice8::EnumEffects(THIS_ LPDIENUMEFFECTSCALLBACK lpCallback,  LPVOID pvRef, DWORD dwEffType){
	Log::log("WrapperDirectInputDevice8::EnumEffects() called!\n");
	HRESULT hr = m_device->EnumEffects(lpCallback,pvRef,dwEffType);
	// send calls, what about the callback function? Ignore it

	return hr;
}
/*
Enumerates all the effects in a file created by the Force Editor utility or another application using the same file format.
*/

STDMETHODIMP WrapperDirectInputDevice8::EnumEffectsInFile(THIS_ LPCSTR lpszFileName, LPDIENUMEFFECTSINFILECALLBACK pec, LPVOID pvRef, DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::EnumEffectsInFile() called!\n");
	HRESULT hr = m_device->EnumEffectsInFile(lpszFileName,pec,pvRef,dwFlags);
	return hr;
}
/*
Enumerates the input and output objects available on a device.
*/
STDMETHODIMP WrapperDirectInputDevice8::EnumObjects(THIS_ LPDIENUMDEVICEOBJECTSCALLBACK lpCallback,  LPVOID pvRef, DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::EnumObjects() called!\n");
	HRESULT hr = m_device->EnumObjects(lpCallback,pvRef,dwFlags);
	return hr;
}

/*
Sends a hardware-specific command to the force-feedback driver.
*/
STDMETHODIMP WrapperDirectInputDevice8::Escape(THIS_ LPDIEFFESCAPE pesc){
	Log::log("WrapperDirectInputDevice8::Escape() called!\n");
	HRESULT hr = m_device->Escape(pesc);
	return hr;
}
/*
Obtains the capabilities of the DirectInputDevice object.
*/

STDMETHODIMP WrapperDirectInputDevice8::GetCapabilities(THIS_ LPDIDEVCAPS lpDIDevCaps){
	Log::log("WrapperDirectInputDevice8::GetCapabilities() called!\n");
	HRESULT hr = m_device->GetCapabilities(lpDIDevCaps);
	return hr;
}


/*
change the source of input data. For GetDeviceData, system will obtain two standard input device data together and buffered locally.
For now, system will get input data when mouse data is called, the keyboard data will be getten at the same time.
*/
/* retrieves buffered data from the device*/
STDMETHODIMP WrapperDirectInputDevice8::GetDeviceData(THIS_ DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod,  LPDWORD pdwInOut,  DWORD dwFlags){
	// careful, need to buffer the data of the input device
	// lock the buffer first, use the mutex
	//WaitForSingleObject(hMutexBuffer, INFINITE);

	Log::log("WrapperDirectInputDevice8::GetDeviceData() called! TAG:%c\n",this->tag);
	Log::log("cbObjectData: %d\npdwInOut: %d\n",cbObjectData,*pdwInOut);
	bool need_acquire = true;
	DWORD s = *pdwInOut;
	
	char *p=NULL;
	if(this->tag == 'K'){
	//	p = keyboard;
		Keyboard_events.to_get = s;
		Keyboard_events.dwFlags = dwFlags;
		if(Keyboard_events.acquired == true)// the keyboard data is already
		{
			//all with not be ready the next time, and now there's no need to get the key, just use the buffer
			Keyboard_events.acquired = false;
			Mouse_events.acquired = false;
			need_acquire = false;
		}
		else{
			// Keyboard not ready, need to get data,mouse data will be ready the next time
			Mouse_events.acquired = true;
			Keyboard_events.acquired = false;
		}
	}
	else if(tag == 'M'){
	//	p=(char *)&mouse;
		Mouse_events.to_get = s;
		Mouse_events.dwFlags = dwFlags;
		if(Mouse_events.acquired == true)// the mouse data is already
		{
			//all with not be ready the next time, and now there's no need to get the mouse, just use the buffer
			Keyboard_events.acquired = false;
			Mouse_events.acquired = false;
			need_acquire = false;
		}
		else{
			// mouse not ready, need to get data,keys data will be ready the next time
			Mouse_events.acquired = false;
			Keyboard_events.acquired = true;
		}
	}
	else{
		Log::log("Unknown device\n");
	}
	HRESULT key_hrr,mouse_hrr;
	if(need_acquire == true){
		cs.begin_command(DIDGetDeviceData_Opcode,id);
		cs.write_char(this->tag);
		cs.write_int(Mouse_events.to_get);
		cs.write_int(Mouse_events.dwFlags);
		cs.write_int(Keyboard_events.to_get);
		cs.write_int(Keyboard_events.dwFlags);

		cs.end_command_im();

		// recv the returned value from client
		// the data format will be {HRESULT, Key array size, Mouse array size, Key array, Mouse arrary}

		int len = dis.get_data();
		Log::log("DirectInput receive input data! len:%d\n",len);
		//int len = recv(client.clientSocket,msg,sizeof(msg),0);
		//ReleaseMutex(hMutexBuffer);
		mouse_hrr=dis.read_uint();
		key_hrr = dis.read_uint();
		DWORD key_size = (DWORD)dis.read_uint();
		DWORD mouse_size = (DWORD)dis.read_uint();
		

		int i = 0;
		Keyboard_events.counts = key_size;
		Mouse_events.counts = mouse_size;
		Log::log("key events:%d, mouse events:%d\n", key_size, mouse_size);
		for(i = 0; i<key_size; i++){
			// read the key data to buffer
			 /*DWORD       dwOfs;
			 DWORD       dwData;
			 DWORD       dwTimeStamp;
			 DWORD       dwSequence;
			 UINT_PTR    uAppData;*/
			Keyboard_events.datas[i].dwOfs = dis.read_uint();
			Keyboard_events.datas[i].dwData = dis.read_uint();
			Keyboard_events.datas[i].dwTimeStamp = dis.read_uint();
			Keyboard_events.datas[i].dwSequence = dis.read_uint();
			Keyboard_events.datas[i].uAppData = dis.read_uint();

			/*Keyboard_events.datas[i].dwOfs = READ_DATA(DWORD);
			Keyboard_events.datas[i].dwData = READ_DATA(DWORD);
			Keyboard_events.datas[i].dwTimeStamp = READ_DATA(DWORD);
			Keyboard_events.datas[i].dwSequence = READ_DATA(DWORD);
			Keyboard_events.datas[i].uAppData = READ_DATA(UINT_PTR);*/
		}
		for(i = 0; i< mouse_size; i++){
			Mouse_events.datas[i].dwOfs = dis.read_uint();
			Mouse_events.datas[i].dwData = dis.read_uint();
			Mouse_events.datas[i].dwTimeStamp = dis.read_uint();
			Mouse_events.datas[i].dwSequence = dis.read_uint();
			Mouse_events.datas[i].uAppData = dis.read_uint();

			/*Mouse_events.datas[i].dwOfs = READ_DATA(DWORD);
			Mouse_events.datas[i].dwData = READ_DATA(DWORD);
			Mouse_events.datas[i].dwTimeStamp = READ_DATA(DWORD);
			Mouse_events.datas[i].dwSequence = READ_DATA(DWORD);
			Mouse_events.datas[i].uAppData = READ_DATA(UINT_PTR);*/
		}


		switch(key_hrr){
		case DI_BUFFEROVERFLOW:
			Log::log("return value  DI_BUFFEROVERFLOW\n");
			break;
		case DI_OK:
			Log::log("return value  DI_OK!\n");
			break;
		case DIERR_INPUTLOST:
			Log::log("return value  DIERR_INPUTLOST\n");
			break;
		case DIERR_INVALIDPARAM:
			Log::log("return value  DIERR_INVALIDPARAM!\n");
			break;
		case DIERR_NOTACQUIRED:
			Log::log("return value  DIERR_NOTACQUIRED!\n");
			break;
		case DIERR_NOTBUFFERED:
			Log::log("return value  DIERR_NOTBUFFERED!\n");
			break;
		case DIERR_NOTINITIALIZED:
			Log::log("return value  DIERR_NOTINITIALIZED.!\n");
			break;
			/*case DIERR_NOTINITIALIZED:
			Log::log("return value  DIERR_NOTINITIALIZED!\n");
			break;*/
		default:
			Log::log("return value  error ERROR type!\n");
			break;
		}

		//WriteDIDObjectData(LPDIDEVICEOBJECTDATA a,LPDIDEVICEOBJECTDATA src)
		if(this->tag == 'M'){
			//DWORD re = READ_DATA(DWORD);
			*pdwInOut = Mouse_events.counts;
			LPDIDEVICEOBJECTDATA src = (LPDIDEVICEOBJECTDATA)(Mouse_events.datas);
			for(int i = 0; i< Mouse_events.counts; i++){
				WriteDIDObjectData( (LPDIDEVICEOBJECTDATA)&(rgdod[i]),&(src[i]));
			}
		}
		else if(this->tag == 'K'){
			// get key data from buffer
			*pdwInOut = Keyboard_events.counts;
			LPDIDEVICEOBJECTDATA src = (LPDIDEVICEOBJECTDATA)(Keyboard_events.datas);
	
			for(int i = 0; i< Keyboard_events.counts; i++){
				WriteDIDObjectData( (LPDIDEVICEOBJECTDATA)&(rgdod[i]),&(src[i]));
			}
		}
		else{
			Log::log("Device Error! No such device\n");
			*pdwInOut = 0;
		}
	}
	else{
		// get data from buffer
		if(this->tag == 'M'){
			//DWORD re = READ_DATA(DWORD);
			*pdwInOut = Mouse_events.counts;
			LPDIDEVICEOBJECTDATA src = (LPDIDEVICEOBJECTDATA)(Mouse_events.datas);
			for(int i = 0; i< Mouse_events.counts; i++){
				WriteDIDObjectData( (LPDIDEVICEOBJECTDATA)&(rgdod[i]),&(src[i]));
			}
		}
		else if(this->tag == 'K'){
			// get key data from buffer
			*pdwInOut = Keyboard_events.counts;
			LPDIDEVICEOBJECTDATA src = (LPDIDEVICEOBJECTDATA)(Keyboard_events.datas);
			for(int i = 0; i< Keyboard_events.counts; i++){
				WriteDIDObjectData( (LPDIDEVICEOBJECTDATA)&(rgdod[i]),&(src[i]));
			}
		}
		else{
			*pdwInOut = 0;
			Log::log("Device Error! No such device\n");
		}
	}
	Log::log("actually obtained data: %d\n",*pdwInOut);
	return DI_OK;
	/*
	if(this->tag == 'M')
		return mouse_hrr;
	else if(this->tag == 'K')
		return key_hrr;
		*/
}

/* retrieves buffered data from the device*/


STDMETHODIMP WrapperDirectInputDevice8::GetDeviceInfo(THIS_ LPDIDEVICEINSTANCE pdidi){
	Log::log("WrapperDirectInputDevice8::GetDeviceInfo() called!\n");
	return m_device->GetDeviceInfo(pdidi);
}
struct t_pa{
	HRESULT ret;
	DIMOUSESTATE mouse;
}R_MOUSE;
struct t_pp{
	HRESULT ret;
	char keys[256];
}R_KEY;


STDMETHODIMP WrapperDirectInputDevice8::GetDeviceState(THIS_ DWORD cbData, LPVOID lpvData){
	// get the device states from the virtual device create local
	Log::log("WrapperDirectInputDevice8::GetDeviceState() called!\n");
	char *p=NULL;
	bool need_acquire = true;
	if(this->tag == 'K'){
		p = keyboard;
		
		if(keyboard_acquired == true){
			// once the keyboard be ready now, it stands that, the mouse data has been warpped, and the keyboard will be wrapped now
			need_acquire = false;
			keyboard_acquired = false;
			mouse_acquired = false;
		}
		else{
			// when get keyboard, the mouse data will be ready the next time, and keyboard not ready next
			mouse_acquired = true;
			keyboard_acquired = false;
		}
	}
	else if(tag == 'M'){
		p=(char *)&mouse;
		if(mouse_acquired == true){
			// once the mouse is ready now, it stands that, the keyboard data has been wrapped, and the mouse data will be wrapped now
			need_acquire= false;
			mouse_acquired = false;
			keyboard_acquired = false;
		}
		else{
			// when need to get mouse, the keyboard data will be ready the next time ,and mouse not ready
			keyboard_acquired = true;
			mouse_acquired = false;
		}
	}
	else{
		Log::log("Unknown device\n");
	}
	//HRESULT ht = m_device->GetDeviceState(cbData,lpvData);
	char * ppp = (char *)lpvData;	

	char * p_m = (char *)&mouse;
	DWORD mouse_size = 0;
	DWORD key_size = 0;
	//client.CompressSock = 0;
	if(need_acquire == true){
		// need to acquire input data from client
		cs.begin_command(DIDGetDeviceState_Opcode,id);
		cs.write_char(this->tag);
		cs.end_command_im();
	
		// the received data format will be like, mouse_data_size, keyboard_data_size, mouse_data, keyboard_data_index(s).
		//int len = recv(client.clientSocket,msg,sizeof(msg),0);
		int len = dis.get_data();
		if(len >0){
			// build buffer
			Log::log("recv key or mouse succ! %d\n ",len);
			Log::log("cbdata: %d recv:%d\n",cbData,len);
			//cur_ptr = msg;
			
			mouse_size =(DWORD)dis.read_uint();
			key_size =(DWORD)dis.read_uint();

			/*mouse_size =(DWORD)cs.read_uint();
			key_size = (DWORD)cs.read_uint();*/

			
			int i = 0;
			for(i = 0; i< mouse_size; i++){
				//(*(ppp+i)) = (*(msg+i)); 
				(*(p_m+i)) = dis.read_char(); // write mouse buffer
			}
			// the key data should be generated with all the indexs
			// wrap old data
			if(key_size>0){
				for(i =0;i<256;i++){
					keyboard[i] = 0;
				}
			}
			// build the keyboard buffer
			unsigned char in;
			for(i = 0; i<key_size; i++){
				//in = (*(cur_ptr+i));
				in = dis.read_char();
				keyboard[in] =-128; // write the keyboard buffer
				Log::log("k[%u] = %d\n",in,keyboard[in]);
			}
			// now write return value
			if(this->tag == 'M')
			{
				for( i = 0;i< mouse_size; i++)
					(*(ppp+i)) = p_m[i];
			}
			else if(this->tag == 'K'){
				
				for(i = 0; i< 256; i++)
					(*(ppp+i)) = keyboard[i];
			}
		}
		else{
			Log::log("recv failed!\n");
			Log::log("recv %c data failed!\n",this->tag);
		}
	}
	else{
		// get the device data from local buffer
		Log::log("the %c data get from local buffer\n",this->tag);
		char * p_m = (char*)&mouse;
		int i = 0;
		if(this->tag == 'M'){
			for( i = 0;i< sizeof(DIMOUSESTATE); i++)
				(*(ppp+i)) = p_m[i];
		}else if(this->tag == 'K'){
			for(i = 0; i< 256 ;i++)
				(*(ppp+i)) = keyboard[i];
		}
	}
	return DI_OK;
}


/*
Obtains information about an effect. localed
*/
STDMETHODIMP WrapperDirectInputDevice8::GetEffectInfo(THIS_ LPDIEFFECTINFOA pdei, REFGUID rguid){
	Log::log("WrapperDirectInputDevice8::GetEffectInfo() called!\n");
	return m_device->GetEffectInfo(pdei,rguid);
}
/*
Retrieves the state of the device's force-feedback system. 
not work for now
*/
STDMETHODIMP WrapperDirectInputDevice8::GetForceFeedbackState(THIS_ LPDWORD pdwOut){
	Log::log("WrapperDirectInputDevice8::GetForceFeedbackState() called!\n");
	return m_device->GetForceFeedbackState(pdwOut);
}
/*
Retrieves information about a device image for use in a configuration property sheet. not work for now
*/
STDMETHODIMP WrapperDirectInputDevice8::GetImageInfo(THIS_ LPDIDEVICEIMAGEINFOHEADER lpdiDevImageInfoHeader){
	Log::log("WrapperDirectInputDevice8::GetImageInfo() called !\n");
	return m_device->GetImageInfo(lpdiDevImageInfoHeader);
}
/*
Retrieves information about a device object, such as a button or axis. not work for now
*/
STDMETHODIMP WrapperDirectInputDevice8::GetObjectInfo(THIS_ LPDIDEVICEOBJECTINSTANCE pdidoi, DWORD dwObj,  DWORD dwHow){
	Log::log("WrapperDirectInputDevice8::GetObjectinfo() called!\n");
	return m_device->GetObjectInfo(pdidoi,dwObj,dwHow);
}
/*
Retrieves information about the input device. not work for now
*/
STDMETHODIMP WrapperDirectInputDevice8::GetProperty(THIS_ REFGUID rguidProp, LPDIPROPHEADER pdiph){
	Log::log("WrapperDirectInputDevice8::GetProperty() called!\n");
	return m_device->GetProperty(rguidProp,pdiph);
}
/*
Initializes a DirectInputDevice object. The IDirectInput8::CreateDevice method automatically initializes a device after creating it; applications normally do not need to call this method. not work for now
*/
STDMETHODIMP WrapperDirectInputDevice8::Initialize(THIS_ HINSTANCE hinst,  DWORD dwVersion, REFGUID rguid){
	Log::log("WrapperDirectInputDevice8::Initialize() called\n");
	return m_device->Initialize(hinst,dwVersion,rguid);
}
/*
Retrieves data from polled objects on a DirectInput device. If the device does not require polling, calling this method has no effect. If a device that requires polling is not polled periodically, no new data is received from the device. Calling this method causes DirectInput to update the device state, generate input events (if buffered data is enabled), and set notification events (if notification is enabled).
*/
STDMETHODIMP WrapperDirectInputDevice8::Poll(THIS){
	Log::log("WrapperDirectInputDevice8::poll() called\n");
	return m_device->Poll();
}
/*
Runs the DirectInput control panel associated with this device. If the device does not have a control panel associated with it, the default device control panel is launched.
*/
STDMETHODIMP WrapperDirectInputDevice8::RunControlPanel(THIS_ HWND hwndOwner, DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::RunControlPanel() called\n");
	
	// send to client
	cs.begin_command(DIDRunControlPanel_Opcode, id);
	cs.write_char(this->tag);
	cs.write_uint(dwFlags);
	cs.end_command();
	return m_device->RunControlPanel(hwndOwner,dwFlags);
}
/*
Sends data to a device that accepts output.
now just ignore
*/
STDMETHODIMP WrapperDirectInputDevice8::SendDeviceData(THIS_ DWORD cbObjectData,  LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD fl){
	Log::log("WrapperDirectInputDevice8::SendDeviceData() called!\n");
	return m_device->SendDeviceData(cbObjectData,rgdod,pdwInOut,fl);
}
/* ignore */
STDMETHODIMP WrapperDirectInputDevice8::SendForceFeedbackCommand(THIS_ DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::SendForceFeedbackCommand() called!\n");
	return m_device->SendForceFeedbackCommand(dwFlags);
}
/*
Sets the data format for a device and maps application-defined actions to device objects. It also sets the buffer size for buffered data.
*/
STDMETHODIMP WrapperDirectInputDevice8::SetActionMap(THIS_ LPDIACTIONFORMATA lpdiActionFormat,  LPCSTR lptszUserName,DWORD dwFlags){
	// the action map may be need to send to the client
	Log::log("WrapperDirectInputDevice8:SetActionMap() called\n");
	Log::log("user name:%d (may be NULL)\n",lptszUserName);
	Log::log("The DIACTIONFORMAT:\n");

	Log::log("not concerned for now\n");


	switch(dwFlags){
	case DIDSAM_DEFAULT:
		Log::log("dwFlags: DIDSAM_DEFAULT\n");
		break;
	case DIDSAM_FORCESAVE:
		Log::log("dwFlags: DIDSAM_FORCESAVE\n");
		break;
	case DIDSAM_NOUSER:
		Log::log("dwFlags: DIDSAM_NOUSER\n");
		break;
	default:
		Log::log("dwFlags: not pre-defined\n");
		break;
	}

	cs.begin_command(DIDSetActionMap_Opcode, id);
	cs.write_char(this->tag);
	//cs.write_uint(*lpdiActionFormat); //error
	cs.write_uint(dwFlags);
	cs.end_command();
	Log::log("WrapperDirectInputDevice8::SetActionMap() end\n");
	return m_device->SetActionMap((LPDIACTIONFORMATA)lpdiActionFormat,lptszUserName,dwFlags);
	
}
// this function is called!
STDMETHODIMP WrapperDirectInputDevice8::SetCooperativeLevel(THIS_ HWND hwnd, DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::SetCooperativeLevel() called!\n");
	// send data to client
	//GET_BUFFER(DIDSetCooperativeLevel_Opcode,id);



	return m_device->SetCooperativeLevel(hwnd,dwFlags);
}
/*
Sets the data format for the DirectInput device.
lpdf
Address of a structure that describes the format of the data that the        DirectInputDevice should return. An application can define its own DIDATAFORMAT structure or use one of the following predefined global variables: 
c_dfDIKeyboard 

c_dfDIMouse 

c_dfDIMouse2 

c_dfDIJoystick 

c_dfDIJoystick2 

*/
STDMETHODIMP WrapperDirectInputDevice8::SetDataFormat(THIS_ LPCDIDATAFORMAT lpdf){
	// may be need to notify the client
	Log::log("WrapperDirectInputDevice::SetDataFormat() called!\n");
	//GET_BUFFER(DIDSetDataFormat_Opcode, id);
	////WRITE_DATA(DIDATAFORMAT ,*lpdf);
	////WRITE_DATA(DIOBJECTDATAFORMAT,lpdf->rgodf);

	//
	//if(this->tag == 'M')
	//{
	//	WRITE_DATA(char,'M');
	//}else if(this->tag == 'K'){
	//	WRITE_DATA(char,'K');
	//}
	//else{
	//	WRITE_DATA(char,0);
	//	Log::log("Device not standard\n");
	//}
	//END_BUFFER();
	//int * tm =(int *) &(*lpdf);
	Log::log("lpdf %d k:%d M1:%d M2:%d J:%d",lpdf,&c_dfDIKeyboard,&c_dfDIMouse,&c_dfDIMouse2,&c_dfDIJoystick);
	
	Log::log("the DIDATAFORMAT struct:\n");
	Log::log("dwSize:%d\n",lpdf->dwSize);
	Log::log("dwObjSize:%d\n",lpdf->dwObjSize);
	Log::log("dwFlags:%d\n",lpdf->dwFlags);
	Log::log("dwDataSize:%d\n",lpdf->dwDataSize);
	Log::log("dwNumObjs:%D\n",lpdf->dwNumObjs);

	
	//client.SendPacket(msg, buf_size);

	Log::log("WrapperDirectInputDevice8::SetDataFormat() end\n");
	return m_device->SetDataFormat(lpdf);
}

STDMETHODIMP WrapperDirectInputDevice8::SetEventNotification(THIS_ HANDLE hEvent){
	// see the details
	Log::log("WrapperDirectInputDevice8::SetEventNotification() called!\n");
	return m_device->SetEventNotification(hEvent);
}
STDMETHODIMP WrapperDirectInputDevice8::SetProperty(THIS_ REFGUID rguidProp,  LPCDIPROPHEADER pdiph){
	Log::log("WrapperDirectInputDevice8::SetProperty() called!\n");
	//Log::log("param: GUID:%d %d %d\n",rguidProp,rguidProp,rguidProp);
	cs.begin_command(DIDSetProperty_Opcode,id);
	cs.write_char(this->tag);

	//DIPROP_APPDATA 
	/*WRITE_DATA(unsigned long,rguidProp.Data1);
	WRITE_DATA(unsigned short,rguidProp.Data2);
	WRITE_DATA(unsigned short,rguidProp.Data3);
	WRITE_DATA(unsigned char,rguidProp.Data4[0]);
	WRITE_DATA(unsigned char,rguidProp.Data4[1]);
	WRITE_DATA(unsigned char,rguidProp.Data4[2]);
	WRITE_DATA(unsigned char,rguidProp.Data4[3]);
	WRITE_DATA(unsigned char,rguidProp.Data4[4]);
	WRITE_DATA(unsigned char,rguidProp.Data4[5]);
	WRITE_DATA(unsigned char,rguidProp.Data4[6]);
	WRITE_DATA(unsigned char,rguidProp.Data4[7]);
	WRITE_DATA(DIPROPHEADER,*pdiph);*/
	//WRITE_DATA(DIPROPHEADER, *pdiph);

	cs.write_uint(pdiph->dwHeaderSize);
	cs.write_uint(pdiph->dwObj);
	cs.write_uint(pdiph->dwHow);

	cs.end_command();
	return m_device->SetProperty(rguidProp,pdiph);

}
STDMETHODIMP WrapperDirectInputDevice8::Unacquire(THIS){
	// notify the client
	Log::log("WrapperDirectInputDevice8:Unacquire() called!\n");
	// send to client
	cs.begin_command(DIDUnacquire_Opcode, id);
	cs.write_char(this->tag);
	cs.end_command();
	return m_device->Unacquire();
}
STDMETHODIMP WrapperDirectInputDevice8::WriteEffectToFile(THIS_ LPCSTR lpszFileName, DWORD dwEntries,  LPDIFILEEFFECT rgDiFileEft,  DWORD dwFlags){
	Log::log("WrapperDirectInputDevice8::WriteEffectToFile() called!\n");
	return m_device->WriteEffectToFile(lpszFileName,dwEntries,rgDiFileEft,dwFlags);
}